use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::time::Duration;
use std::fs;
use std::thread;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;


type Job = Box<dyn FnOnce() + Send + 'static>;

pub struct Worker {
    id: usize,
    thread: thread::JoinHandle<()>,
}

impl Worker {
    pub fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
        let thread = thread::spawn(
            move || loop {
                // loop，let语句完成后，可以退出上下文，mutex自动解锁。
            let job = receiver.lock().unwrap().recv().unwrap();

            println!("Worker {} got a job; executing.", id);

            job();
        });
        Worker { id, thread }
    }
}

pub struct ThreadPool {
    workers: Vec<Worker >,
    sender: mpsc::Sender<Job>,
}

impl ThreadPool {
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);
        let mut workers = Vec::with_capacity(size);
        let (sender, receiver) = mpsc::channel();
        let receiver = Arc::new(Mutex::new(receiver));
        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }
        ThreadPool{ workers, sender}
    }

    pub fn execute<F>(&self, f:F)
    where F: FnOnce() + Send + 'static {
        // 静态引用，通过Box将其生成周期转到Worker内部。
        let job = Box::new(f);
        self.sender.send(job).unwrap();
    }
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();

    let pool = ThreadPool::new(4);

    for stream in listener.incoming() {
        let stream = stream.unwrap();

        println!("Connection established!");
        pool.execute(
            || {
                handle_connection(stream);
            }
        );
    }
}


fn handle_connection(mut stream: TcpStream) {
    // buffer的声明方式，‘;’后跟的长度。
    let mut buffer = [0; 1024];

    // println!("buffer {:?}", buffer);
    stream.read(&mut buffer).unwrap();
    println!("Result: {}", String::from_utf8_lossy(&buffer[..]));
    let get = b"GET / HTTP/1.1\r\n";
    let sleep = b"GET /sleep HTTP/1.1\r\n";
    let (status_line, filename) = if buffer.starts_with(get) {
        ("HTTP/1.1 200 OK\r\n\r\n", "hello.html")
    } else if buffer.starts_with(sleep) {
        thread::sleep(Duration::from_secs(5));
        ("HTTP/1.1 200 OK\r\n\r\n", "hello.html")
    } else {
        ("HTTP/1.1 404 NOT FOUND\r\n\r\n", "404.html")
    };

    let contents = fs::read_to_string(filename).unwrap();

    let response = format!(
        "{}Content-Length:{}\r\n\r\n{}",
        status_line,
        contents.len(),
        contents,
        );
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}
